home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PCMania 44
/
PCMania CD44_1.iso
/
pcmania
/
babel44
/
goraudg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-30
|
29KB
|
1,027 lines
#include <pc.h>
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <math.h>
#include <graphics.h>
unsigned int searchtext(unsigned char *, unsigned char *,
unsigned int, FILE *);
unsigned int sigword(unsigned char *, unsigned int);
unsigned int tomanombre(unsigned char *, unsigned char *, unsigned int);
unsigned int tomanom_s(unsigned char *, unsigned char *, unsigned int);
void cargar(FILE *);
void initmatT(void);
void scale(float, float, float);
void rotate(float, float, float);
void translate(float, float, float);
void transform(void);
void project(void);
void dibujar(void);
void matmul(float *, float *);
void calnor(unsigned short);
unsigned char colver(unsigned short, unsigned char);
void borrap(void);
void Bresen(unsigned short, unsigned short, unsigned short,
unsigned short, unsigned short);
void interpolateY(unsigned short, unsigned char, unsigned short,
unsigned char, unsigned short);
void interpolateX(unsigned short, unsigned short);
struct yuyu{
unsigned short npol; /* num. absoluti de poligono (indice a caras[]) */
short prof; /* profundidad de este */
};
int comp(const struct yuyu *a, const struct yuyu *b);
#define maxlon 40960
unsigned char bufferR[maxlon]; /* buffer para datos de F. a leer */
FILE *fichasc; /* handle para fichero .asc a leer */
unsigned int posr; /* pos. relativa dentro del buffer */
unsigned char string[50]; /* cadenas de trabajo */
unsigned char string1[50];
unsigned char nombref[30];
unsigned char mam[30];
unsigned char mam1[30];
unsigned nvertices,nfaces; /* num. de vertices y caras de objeto unico */
float matT[4][4]; /* Matriz de transformación global */
float mat[4][4]; /* matriz de trabajo */
unsigned long nvert; /* num. de vertices del objeto basico */
unsigned long ntri; /* num. de triangulos */
unsigned long tri; /* contador */
float vertic[40000][3]; /* hay un max. de 40000 trian. tratables.
La primera dim. es el num. de vertice y la segunda guarda la X, Y o Z */
unsigned short caras[40000][3];
struct yuyu caraZ[40000]; /* espacio para 40000 profundidades Z */
double normca[40000][3]; /* espacio para almacenar las normales de 40000
caras */
/* reservamos espacio para calcular las coords. finales de cada vert. */
float vtra[40000][3];
/* y tambien el corresp. espacio para las coords. de pantalla */
short vpant[40000][2];
/* en cavert[] se guarda, por cada vertice, la lista de caras en las que
interviene. (Para saber con rapidez los poligonos cuyas normales tienen
que promediarse para hallar el color de cada vertice). icaver[] tiene
los indices a cavert[] de cada vertice */
unsigned short cavert[40000*4];
unsigned short icaver[40000];
unsigned short pcavert; /* indice al primer registro cavert[] libre */
int nobj; /* num. de objeto en curso */
float xMen;
float xMay;
float yMen;
float yMay;
float zMen;
float zMay; /* coords. maximas XYZ del objeto */
float trab;
float radgra; /* para la conver. de grados a rad. */
double xluz,yluz,zluz; /* posicion de la fuente de luz */
double var1,var2,var3; /* valores interm. para calc. de vector unidad */
double xluni,yluni,zluni; /* el vector unidad de la fuente de luz */
unsigned char palet; /* flag. para indicar la micropaleta en curso */
unsigned short tfil[1200]; /* tabla temporal para limites X de llenado del
poligono en curso */
unsigned char tfilc[1200]; /* tabla temporal para colores Goraud de aristas
de triangulo en curso. (Luego el interior se
llena por interpolación) */
main()
{
unsigned int a,b,c,d,e;
float xang,yang,zang; /* angulos de rotación */
float xinc,yinc,zinc; /* incrementos para las rotat. */
float ix,iy,iz; /* para la traslación */
float sx,sy,sz; /* escala */
unsigned short v;
unsigned char string[50]; /* cadenas de trabajo */
unsigned char mam[30];
char tecla;
float increm;
float col;
unsigned char oboluz; /* si=0, las ords. de mov. afectan a los obj.
si no, afectan a la pos. del punto de luz */
oboluz=0;
xMen=0;
yMen=0;
zMen=0;
xMay=0;
yMay=0;
zMay=0; /* hay que conocer los extremos del ob. */
ntri=0;
radgra=.01744;
posr=0;
puts(" Solid 0.91 por Jose Manuel Muñoz Perez\n");
system("dir /w *.asc");
printf("indica el fichero (ASC) de 3d Studio a tratar ");
scanf("%s",mam);
strcpy(string,mam);
strcat(string,".asc");
if ((fichasc=fopen(string,"r"))==0)
{
printf("\n Error: El fichero no puede abrirse!\n\n");
exit(1);
}
cargar(fichasc); /* cargar 70 lineas del f. */
posr=0;
posr=searchtext(bufferR,"Named object:",posr,fichasc);
while (posr!=65535)
{
/* buscar objeto */
posr=sigword(bufferR,posr);/* nos posicionamos sobre el nombre del objeto */
posr++; /* nos saltamos las comillas del nombre */
posr=tomanombre(bufferR,mam,posr);
/* metemos el nombre del objeto en 'mam' */
a=strlen(mam);
mam[a-1]=0; /* quitamos las comillas del nombre poniendo
un 0 (fin de cadena, ¿recuerdan?) */
posr=sigword(bufferR,posr);/* nos posicionamos sobre la siguiente palabra
(el tipo de objeto; Camera, Direct light, Tri-mesh (objeto)) */
posr=tomanom_s(bufferR,mam1,posr);
printf("leyendo objeto ");
printf("%s\n",mam);
/* ya tenemos el tipo de objeto en mam1[] */
if (!strcmp(mam1,"Camera"))
{ /* la camara no nos interesa aqui */
posr=searchtext(bufferR,"Named object:",posr,fichasc);
continue;
}
else if (!strcmp(mam1,"Direct"))
{ /* por "Direct light" */
posr=searchtext(bufferR,"Position:",posr,fichasc);
posr=searchtext(bufferR,"X:",posr,fichasc);
xluz=atof(bufferR+posr);
posr=searchtext(bufferR,"Y:",posr,fichasc);
zluz=atof(bufferR+posr);
posr=searchtext(bufferR,"Z:",posr,fichasc);
yluz=atof(bufferR+posr);
posr=searchtext(bufferR,"Named object:",posr,fichasc);
/* recordemos que hay que invertir Y y Z */
continue;
}
else if (!strcmp(mam1,"Tri-mesh,"))
{
posr=searchtext(bufferR,"Vertices:",posr,fichasc);
posr++; /* saltar espacio en blanco */
nvertices=atoi(bufferR+posr);
posr=searchtext(bufferR,"Faces:",posr,fichasc);
posr++; /* saltar espacio en blanco */
nfaces=atoi(bufferR+posr);
/* ahora tomar los vertices. Primero nos situamos en el primero -el 0 */
posr=searchtext(bufferR,"Vertex 0:",posr,fichasc);
for (a=0;a<nvertices;a++)
{
posr=searchtext(bufferR,"X:",posr,fichasc);
vertic[a][0]=atof(bufferR+posr);
/* ahora recordemos que 3D Studio invierte Y y Z con respecto al sistema
"izquierdo" que empleamos nosotros */
posr=searchtext(bufferR,"Y:",posr,fichasc);
/* el *(-1) es para que los modelos queden "de frente" */
vertic[a][2]=(atof(bufferR+posr))*(-1);
posr=searchtext(bufferR,"Z:",posr,fichasc);
vertic[a][1]=atof(bufferR+posr);
if (vertic[a][0]<xMen)
xMen=vertic[a][0];
if (vertic[a][1]<yMen)
yMen=vertic[a][1];
if (vertic[a][2]<zMen)
zMen=vertic[a][2];
if (vertic[a][0]>xMay)
xMay=vertic[a][0];
if (vertic[a][1]>yMay)
yMay=vertic[a][1];
if (vertic[a][2]>zMay)
zMay=vertic[a][2];
}
/* ahora tomaremos los datos de la lista de caras */
posr=searchtext(bufferR,"Face list:",posr,fichasc);
for (a=0;a<nfaces;a++)
{
posr=searchtext(bufferR,"Face ",posr,fichasc);
posr=searchtext(bufferR," A:",posr,fichasc);
caras[a][0]=atoi(bufferR+posr); /* tomar 1er vertice del trian. */
posr=searchtext(bufferR," B:",posr,fichasc);
caras[a][1]=atoi(bufferR+posr); /* tomar 2ndo vertice del trian. */
posr=searchtext(bufferR," C:",posr,fichasc);
caras[a][2]=atoi(bufferR+posr); /* tomar 3er vertice del trian. */
}
/* mirar si hay mas objetos */
posr=searchtext(bufferR,"Named object:",posr,fichasc);
}
}
/* Se acabo la lectura */
fclose(fichasc);
/* YA LO HEMOS LEIDO TODO */
/* ahora, antes de visualizar, construimos tablas cavert[] e icaver[] */
puts("Construyendo registros con caras donde aparece cada vertice (paciencia)");
pcavert=0;
for (a=0,c=0;a<nvertices;a++)
{
icaver[c]=pcavert;
c++;
for (b=0;b<nfaces;b++)
{
if (a==caras[b][0] || a==caras[b][1] || a==caras[b][2])
{
cavert[pcavert]=b;
pcavert++;
}
}
}
icaver[c]=pcavert;
xang=0; yang=0; zang=0;
xinc=0; yinc=0; zinc=0;
sx=1; sy=1; sz=1;
ix=0; iy=0;
trab=xMay+fabs(xMen);
if (trab<yMay+fabs(yMen))
trab=yMay+fabs(yMen);
if (trab<zMay+fabs(zMen))
trab=zMay+fabs(zMen);
if (xMay>+fabs(xMen))
ix=((xMay-fabs(xMen))/2)*(-1);
else
ix=(fabs(xMen)-xMay)/2;
if (yMay>+fabs(yMen))
iy=((yMay-fabs(yMen))/2)*(-1);
else
iy=(fabs(yMen)-yMay)/2;
if (zMay>+fabs(zMen))
iz=((zMay-fabs(zMen))/2)*(-1);
else
iz=(fabs(zMen)-zMay)/2;
iz+=(trab*4)*(-1);
zluz-=(trab*4)*(-1);
increm=trab/3;
GrSetMode(GR_default_graphics);
/* creamos dos paleta de 128 tonos de color para los sombreados a partir
de la posición 0 de la paleta global de 256 tonos */
for (col=0,v=0;v<128;v++)
{
/* paleta "roja" */
col+=1.5;
GrSetColor(v,col,0,0);
}
for (col=0,v=0;v<128;v++)
{
/* paleta "blanca" */
col+=1.5;
GrSetColor(v+128,col,col,col);
}
palet=1; /* empezar apuntando a la paleta roja */
tecla=0;
while (tecla!=27)
{ /* rotar mientras no se pulse una tecla */
initmatT(); /* inicializar matriz global */
scale(sx,sy,sz);
xang+=xinc;
yang+=yinc;
zang+=zinc;
rotate(xang,yang,zang);
translate(ix,iy,iz);
/* sigue el borrado de pantalla */
borrap();
transform();
project();
/* ahora hallar el vector unidad de la fuente de luz */
var1=(xluz*xluz) + (yluz*yluz) + (zluz*zluz);
var2=sqrt(var1);
if (var2==0)
var2=0.001;
var3=1/var2;
xluni=xluz*var3;
yluni=yluz*var3;
zluni=zluz*var3;
dibujar();
xinc=0; yinc=0; zinc=0; /* resetear increms. de angulos */
aagh:
tecla=getkey();
switch(tecla)
{
/* con la tecla i se intercambia el funcionamiento de las teclas para los
modelos o las fuentes de luz */
case 'i':
if (oboluz==0)
oboluz=1;
else
oboluz=0;
break;
case 'c': /* cambiar el color del objeto */
if (palet<2)
palet++;
else
palet=1;
break;
case 'g': /* hacer mas pequeños los desplazamientos */
increm/=2;
break;
case 'h': /* hacer mas grandes los desplazamientos */
increm*=2;
break;
case 'n':
if (oboluz==0)
iz+=increm; /* acercar objeto o fuente */
else
zluz+=increm;
break;
case 'm':
if (oboluz==0)
iz-=increm; /* alejar */
else
zluz-=increm;
break;
case 'q':
if (oboluz==0)
iy+=increm; /* arriba */
else
yluz+=increm;
break;
case 'a':
if (oboluz==0)
iy-=increm; /* abajo */
else
yluz-=increm;
break;
case 'o':
if (oboluz==0)
ix-=increm; /* izquierda */
else
xluz-=increm;
break;
case 'p':
if (oboluz==0)
ix+=increm; /* derecha */
else
xluz+=increm;
break;
case '1':
xinc=10*radgra; /* casos de rotaciones */
break;
case '2':
xinc=-10*radgra;
break;
case '3':
yinc=10*radgra;
break;
case '4':
yinc=-10*radgra;
break;
case '5':
zinc=10*radgra;
break;
case '6':
zinc=-10*radgra;
break;
case 27:
exit(0); /* se acabo */
default :
goto aagh; /* ¡horror! ¡un goto! */
}
}
getkey();
}
/* Esta funcion busca una cadena de texto dentro de un array de caracteres.
Devuelve 65535 si no lo ha hallado o un valor entero indicando su pos.
en dicho array. La funcion acepta como parametros un puntero a la cadena
donde va a efectuarse la busqueda, otro puntero a la cadena que se va a
buscar y un indice al punto de principio para la busqueda (puede ser
preciso que la investigacion no comienze desde el principio).
Cuando una ocurrencia sobrepase las ultimas lineas de la carga anterior
se leera otra tanda de lineas (por ello tambien adjuntamos el puntero
*FILE al fichero que deseamos leer). logicamente en ese caso el indice
a devolver continuara la busqueda desde 0 */
unsigned int searchtext(unsigned char *buffer, unsigned char *text,
unsigned int desp, FILE *fich)
{
long a,b,c;
unsigned char loncad;
int d;
a=0;
loncad=strlen(text);
sigcar:
while(buffer[desp]!=text[a] && buffer[desp]!=255 && buffer[desp]!=0)
desp++;
if (buffer[desp]==255)
{
cargar(fich); /* leer mas lineas */
desp=0;
goto sigcar;
}
if (buffer[desp]==0)
return(65535); /* marca de que no se ha hallado correspondencia */
/* si llega aqui, es que se ha leido el car. */
d=desp;
for (b=0,c=desp;b<loncad-1;a++,b++,c++)
{
if (buffer[c]!=text[a])
{
a=0;
desp++;
goto sigcar;
}
}
a=d+loncad;
return (a);
/* a=d+loncad es porque el indice devuelto corresponde a la primera pos.
del array, despues de la ocurrencia hallada */
}
/* llamamos a sigword() cuando deseamos hallar el indice dentro del array
a la sig. palabra que sigue a la ultima procesada (indicada por desp) */
unsigned int sigword(unsigned char *buffer, unsigned int desp)
{
/* primero nos saltamos los car. de la palabra actual */
while(buffer[desp]!=32 && buffer[desp]!=13 &&
buffer[desp]!=10 && buffer[desp]!=255)
desp++;
if (bufferR[desp]==255)
{ /* ultima linea de carga anterior */
cargar(fichasc); /* leer otra tanda de lineas */
desp=0;
}
/* y ahora los espacios hasta la siguiente palabra */
while((buffer[desp]==32 || buffer[desp]==13 || buffer[desp]==10) &&
buffer[desp]!=255)
desp++;
if (bufferR[desp]==255)
{
cargar(fichasc);
desp=0;
}
return desp;
}
/* toma el nombre alterando algunos caracteres que no permite el POV */
unsigned int tomanombre(unsigned char *buffer,
unsigned char *text, unsigned int desp)
{
unsigned char a;
a=0;
while(buffer[desp]!=32 && buffer[desp]!=13 && buffer[desp]!=10)
{
if ((buffer[desp]>=48 && buffer[desp]<=57) || buffer[desp]=='"' ||
(buffer[desp]>=65 && buffer[desp]<=90) ||
(buffer[desp]>=97 && buffer[desp]<=122))
text[a]=buffer[desp]; /* es uno de los car. permitidos por POV */
else
text[a]='_';
a++;
desp++;
}
text[a]=0; /* marca para fin de cadena */
return desp;
}
/* toma el nombre sin alteraciones */
unsigned int tomanom_s(unsigned char *buffer,
unsigned char *text, unsigned int desp)
{
unsigned char a;
a=0;
while(buffer[desp]!=32 && buffer[desp]!=13 && buffer[desp]!=10)
{
text[a]=buffer[desp];
a++;
desp++;
}
text[a]=0; /* marca para fin de cadena */
return desp;
}
/* ahora leer 80 lineas como maximo a partir de bufferR+0 */
void cargar(FILE *fich)
{
unsigned int a,b,c;
for (a=0,b=80;b!=0;b--)
{
if (!feof(fich))
{
fgets(bufferR+a,512,fich);
for (c=a;c<a+512;c++)
{
if (bufferR[c]==0)
break;
}
a=c;
}
else
{
bufferR[c]=0; /* marca de final de fichero */
return;
}
}
bufferR[c]=255; /* marca de ultima de las 80 lineas */
}
/* EMPIEZAN LAS FUNCIONES 3D PROPIAMENTE DICHAS */
/* Incializa la matriz de transformación global */
void initmatT(void)
{
matT[0][0]=1; matT[0][1]=0; matT[0][2]=0; matT[0][3]=0;
matT[1][0]=0; matT[1][1]=1; matT[1][2]=0; matT[1][3]=0;
matT[2][0]=0; matT[2][1]=0; matT[2][2]=1; matT[2][3]=0;
matT[3][0]=0; matT[3][1]=0; matT[3][2]=0; matT[3][3]=1;
}
/* crea la matriz de escalación y la multiplica por la global */
void scale(float sX, float sY, float sZ)
{
/* inicialización de la matriz de trabajo para escalar */
mat[0][0]=sX; mat[0][1]=0; mat[0][2]=0; mat[0][3]=0;
mat[1][0]=0; mat[1][1]=sY; mat[1][2]=0; mat[1][3]=0;
mat[2][0]=0; mat[2][1]=0; mat[2][2]=sZ; mat[2][3]=0;
mat[3][0]=0; mat[3][1]=0; mat[3][2]=0; mat[3][3]=1;
/* Concatenación con la matriz maestra, el result. queda en matT */
matmul(mat,matT);
}
/* crea las matrices de rotación para cada eje y las va concatenando con
la matriz de transformación global */
void rotate(float aX,float aY,float aZ)
{
if (aX!=0)
{
/* Inicializar rotación en X */
mat[0][0]=1; mat[0][1]=0; mat[0][2]=0; mat[0][3]=0;
mat[1][0]=0; mat[1][1]=cos(aX); mat[1][2]=sin(aX); mat[1][3]=0;
mat[2][0]=0; mat[2][1]=-sin(aX); mat[2][2]=cos(aX); mat[2][3]=0;
mat[3][0]=0; mat[3][1]=0; mat[3][2]=0; mat[3][3]=1;
/* concatenarla con la maestra */
matmul(mat,matT);
}
if (aY!=0)
{
/* Inicializar rotación en Y */
mat[0][0]=cos(aY); mat[0][1]=0; mat[0][2]=-sin(aY); mat[0][3]=0;
mat[1][0]=0; mat[1][1]=1; mat[1][2]=0; mat[1][3]=0;
mat[2][0]=sin(aY); mat[2][1]=0; mat[2][2]=cos(aY); mat[2][3]=0;
mat[3][0]=0; mat[3][1]=0; mat[3][2]=0; mat[3][3]=1;
/* concatenarla con la maestra */
matmul(mat,matT);
}
if (aZ!=0)
{
/* Inicializar rotación en Z */
mat[0][0]=cos(aZ); mat[0][1]=sin(aZ); mat[0][2]=0; mat[0][3]=0;
mat[1][0]=-sin(aZ); mat[1][1]=cos(aZ); mat[1][2]=0; mat[1][3]=0;
mat[2][0]=0; mat[2][1]=0; mat[2][2]=1; mat[2][3]=0;
mat[3][0]=0; mat[3][1]=0; mat[3][2]=0; mat[3][3]=1;
/* concatenarla con la maestra */
matmul(mat,matT);
}
}
/* crea la matriz de traslación y la multiplica por la global. Con esta
matriz trasladaremos al objeto desde su pos. inicial en el centro del
universo a las coords. de vision una distancia tX, tY y tZ */
void translate(float tX, float tY, float tZ)
{
mat[0][0]=1; mat[0][1]=0; mat[0][2]=0; mat[0][3]=0;
mat[1][0]=0; mat[1][1]=1; mat[1][2]=0; mat[1][3]=0;
mat[2][0]=0; mat[2][1]=0; mat[2][2]=1; mat[2][3]=0;
mat[3][0]=tX; mat[3][1]=tY; mat[3][2]=tZ; mat[3][3]=1;
/* Concatenacion con la matriz de transform. global */
matmul(matT,mat);
}
void matmul(float *mat1, float *mat2)
{
unsigned char i,j,k;
float matra[4][4]; /* Matriz temporal */
/* y ahora realizamos la multiplicación propiamente dicha */
for (i=0; i<4; i++)
for (j=0; j<4; j++)
{
matra[i][j]=0;
for (k=0; k<4; k++)
matra[i][j]+=(*(mat1+(i*4)+k)) * (*(mat2+(k*4)+j));
}
/* el resultado acaba siempre en la matriz de transformacion */
for (i=0; i<4; i++)
for (j=0; j<4; j++)
matT[i][j]=matra[i][j];
}
/* multiplicamos todos los vertices del cubo por la matriz de transformación
global para obtener las coordenadas visuales del objeto */
void transform(void)
{
unsigned short v;
float x,y,z;
for (v=0; v<nvertices; v++)
{
x=vertic[v][0];
y=vertic[v][1];
z=vertic[v][2];
/* calcular vertices "transformados a su pos. final en el espacio */
vtra[v][0]=x*matT[0][0] + y*matT[1][0] + z*matT[2][0] + matT[3][0];
vtra[v][1]=x*matT[0][1] + y*matT[1][1] + z*matT[2][1] + matT[3][1];
vtra[v][2]=x*matT[0][2] + y*matT[1][2] + z*matT[2][2] + matT[3][2];
}
}
/* ahora proyectamos las coordenadas visuales halladas (vcubos[]) en la
pantalla aplicando esta función para la perspectiva */
void project(void)
{
unsigned short p,v;
int distancia;
for (p=0,v=0,distancia=1000; v<nvertices; v++)
{
vpant[v][0]=(distancia*vtra[v][0]/vtra[v][2])*(-1);
vpant[v][1]=distancia*vtra[v][1]/vtra[v][2];
}
}
/* Dibujar la forma */
void dibujar(void)
{
unsigned short a,b,c,d,e,f,g;
long vi;
float x1,y1,z1, x2,y2,z2, x3,y3,z3, zm;
short h,i,j;
double col;
unsigned char color;
unsigned short coord[12]; /* 2 veces las coords. de pantalla de 3 vert. */
unsigned char colv[7]; /* 2 veces los colores de tres vert. */
for (a=0,b=0; a<nfaces; a++)
{
x1=vtra[caras[a][0]][0];
x2=vtra[caras[a][1]][0];
x3=vtra[caras[a][2]][0];
y1=vtra[caras[a][0]][1];
y2=vtra[caras[a][1]][1];
y3=vtra[caras[a][2]][1];
z1=vtra[caras[a][0]][2];
z2=vtra[caras[a][1]][2];
z3=vtra[caras[a][2]][2];
vi=(x3*((z1*y2)-(y1*z2))) + (y3*((x1*z2)-(z1*x2))) + (z3*((y1*x2)-(x1*y2)));
if (vi<0)
continue;
zm=z1+z2+z3/3; /* Z promediada de los tres vertices */
caraZ[b].prof=zm; /* profundidad media */
caraZ[b].npol=a; /* num. absoluto del poligono */
/* calcular y guardar la normal del poligono visible */
calnor(a); /* calcula la normal del pol. */
b++;
}
/* seguidamente clasificamos las profundidades usando qsort() */
/* qsort(caraZ,b,4,(unsigned short(*)(const short *,const short *)) comp);*/
qsort(caraZ,b,4, comp);
for (a=0;a<b;a++)
{
/* Seguidamente se calcula el color de cada vertice del poligono visible en
curso */
c=caraZ[a].npol; /* num. absoluto del poligono */
for (d=0;d<3;d++)
{ /* mirar tres vertices */
e=caras[c][d]; /* numero absoluto del vertice */
f=icaver[e]; /* indice a registro de caras de este vertice */
for (var1=0,var2=0,var3=0,g=0;g<icaver[e+1]-icaver[e];g++)
{
/* sumamos las normales de las caras en las que interviene el vert. */
var1+=normca[cavert[f+g]][0];
var2+=normca[cavert[f+g]][1];
var3+=normca[cavert[f+g]][2];
}
var1/=(icaver[e+1]-icaver[e]);
var2/=(icaver[e+1]-icaver[e]);
var3/=(icaver[e+1]-icaver[e]);
/* ya tenemos la normal promediada para el vertice */
/* ahora obtendremos el valor de 0 a 1 que indica el grado de iluminación */
col=(var1*xluni)+(var2*yluni)+(var3*zluni);
/* El angulo entre la normal del triangulo y el vector de la fuente de luz
es la relación entre el coseno del angulo y el producto escalar de los
vectores. El rayo de luz es perpendicular a la superficie -maxima luz-
cuando el coseno=1 y es paralelo al poligono -minima ilum.- cuando es =0.
Si el coseno es negativo, el triangulo tomara el valor minimo de luz (o
sea el de la iluminación ambiental que hayamos marcado) ya que la fuente
de luz no incide sobre el poligono (esta "detras") */
if (col<0)
col=0;
else
col*=128;
color=abs(col)+(palet*128);
colv[d]=color;
}
/* ahora efectuamos LA RASTERIZACION.
Primero tomar las coords. de pantalla de los tres vertices */
coord[0]=vpant[caras[c][0]][0]+320;
coord[1]=vpant[caras[c][0]][1]+240;
coord[2]=vpant[caras[c][1]][0]+320;
coord[3]=vpant[caras[c][1]][1]+240;
coord[4]=vpant[caras[c][2]][0]+320;
coord[5]=vpant[caras[c][2]][1]+240;
/* lo que sigue se hace por comodidad */
coord[6]=coord[0];
coord[7]=coord[1];
coord[8]=coord[2];
coord[9]=coord[3];
coord[10]=coord[4];
coord[11]=coord[5];
colv[3]=colv[0];
colv[4]=colv[1];
colv[5]=colv[2];
colv[6]=colv[0];
/* hallar el vertice superior izquierdo */
for (e=0,d=481;e<5;e+=2)
{
if (coord[e+1]<d)
{
d=coord[e+1];
f=e>>1;
}
else if (coord[e+1]==d)
{
if (coord[e]>coord[f<<2])
continue;
else
f=e>>1;
}
}
/* ya tenemos en 'f' el num. de vertice superior izquierdo */
g=f;
f=f<<1;
Bresen(coord[f],coord[f+1],coord[f+2],coord[f+3],0);
/* calc. color de cada punto de la linea */
interpolateY(coord[f+1],colv[g],coord[f+3],colv[g+1],0);
if (coord[f+3]<coord[f+5])
{
Bresen(coord[f+2],coord[f+3],coord[f+4],coord[f+5],0);
interpolateY(coord[f+3],colv[g+1],coord[f+5],colv[g+2],0);
d=f+5;
}
else
{
Bresen(coord[f+2],coord[f+3],coord[f+4],coord[f+5],480);
interpolateY(coord[f+3],colv[g+1],coord[f+5],colv[g+2],480);
d=f+3;
}
if (coord[f+5]!=coord[f+7])
{
Bresen(coord[f+4],coord[f+5],coord[f+6],coord[f+7],480);
interpolateY(coord[f+5],colv[g+2],coord[f+7],colv[g+3],480);
}
/* fill procede a interpolar los colores entre ambas bandas Y */
interpolateX(coord[f+1],coord[d]);
}
}
int comp(const struct yuyu *a, const struct yuyu *b)
{
return (a->prof)-(b->prof);
}
/* hallar la normal del poligono 'np' */
void calnor(unsigned short np)
{
double xi,yi,zi,xf,yf,zf; /* valores intermedios para calculo de normales */
double xnor,ynor,znor; /* normal del poligono */
double xuni,yuni,zuni; /* la normal convertida a vector unidad */
/* calcular vector de vertice 0 al 1 */
xi=vtra[caras[np][1]][0] - vtra[caras[np][0]][0];
yi=vtra[caras[np][1]][1] - vtra[caras[np][0]][1];
zi=vtra[caras[np][1]][2] - vtra[caras[np][0]][2];
/* calcular vector de vertice 0 al 2 */
xf=vtra[caras[np][2]][0] - vtra[caras[np][0]][0];
yf=vtra[caras[np][2]][1] - vtra[caras[np][0]][1];
zf=vtra[caras[np][2]][2] - vtra[caras[np][0]][2];
/* normal del poligono */
xnor= (yi*zf) - (zi*yf); /* X */
ynor= (zi*xf) - (xi*zf); /* Y */
znor= (xi*yf) - (yi*xf); /* Z */
var1=(xnor*xnor) + (ynor*ynor) + (znor*znor);
var2=sqrt(var1);
if (var2==0)
var2=0.001;
var3=1/var2;
xuni= var3*xnor; /* vector unidad de la normal del poligono */
yuni= var3*ynor;
zuni= var3*znor;
/* almacenamos el vector unidad del poligono */
normca[np][0]=xuni;
normca[np][1]=yuni;
normca[np][2]=zuni;
}
/* borrado de pantalla */
void borrap(void)
{
unsigned char *p;
unsigned long a;
p=0xD0000000;
for (a=0;a<307200;a++,p++)
*p=0;
}
/* algoritmo de brasemhan "retocadillo" version 2 */
void Bresen(unsigned short x1, unsigned short y1, unsigned short x2,
unsigned short y2, unsigned short dim)
{
int dx, dy, sx, sy;
int count;
int brc;
unsigned short inter;
/* el bloque de lineas que sigue existe para asegurar que la pendiente
aproximada de la linea sea siempre la misma (prueben a quitarlas */
if (y1>y2)
{
inter=y1;
y1=y2;
y2=inter;
inter=x1;
x1=x2;
x2=inter;
}
sx = sy = 1;
dx = x2 - x1;
dy = y2 - y1;
if (dx < 0)
{
dx *= -1;
sx *= -1;
}
if (dy < 0)
{
dy *= -1;
sy *= -1;
}
if (dx > dy)
{
brc = dx>>1;
tfil[y1+dim]=x1;
for (count = dx; count; count--)
{
x1 += sx;
brc += dy;
if (brc > dx)
{
brc -= dx;
y1 += sy;
tfil[y1+dim]=x1;
}
}
}
else
{
brc = dy>>1;
tfil[y1+dim]=x1;
for (count = dy; count; count--)
{
y1 += sy;
brc += dx;
if (brc > 0)
{
brc -= dy;
x1 += sx;
}
tfil[y1+dim]=x1;
}
}
}
void interpolateY(unsigned short y, unsigned char col, unsigned short y1,
unsigned char col1, unsigned short dim)
{
unsigned short inter;
unsigned char icol;
short a,c;
unsigned short overf;
float calc;
/* primero ponemos los colores en los picos de las bandas */
tfilc[y+dim]=col;
tfilc[y1+dim]=col1;
/* ahora procedemos a interpolar */
if (y1>=y)
{
if (y1-y==0)
overf=1;
else
overf=y1-y;
calc=(col1-col)/(overf);
for (a=0,c=col;a<(y1-y)+1;a++)
{
tfilc[(y+a)+dim]=c;
c+=calc;
}
}
else
{
if (y-y1==0)
overf=1;
else
overf=y-y1;
calc=(col-col1)/(overf);
for (a=0,c=col1;a<(y-y1)+1;a++)
{
tfilc[(y1+a)+dim]=c;
c+=calc;
}
}
}
/* interpolación de color entre las bandas */
void interpolateX(unsigned short ymen, unsigned short ymax)
{
short a,x,y,calc,c;
for (a=0,y=ymen;a<(ymax-ymen)+1;a++,y++)
{
if (tfil[y+480]-tfil[y]==0)
{
GrPlot(tfil[y],y,tfilc[y]);
}
else
{
calc=(tfilc[y+480]-tfilc[y])/(tfil[y+480]-tfil[y]);
for (x=tfil[y],c=tfilc[y];x<tfil[y+480];x++)
{
GrPlot(x,y,c);
c+=calc;
}
}
}
}